﻿using ezCloud.Api.Common;
using ezCloud.Api.Models;
using ezCloud.Data;
using Microsoft.AspNet.Identity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Web.Http;
using System.Threading.Tasks;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;
using Microsoft.Ajax.Utilities;

namespace ezCloud.Api.Controllers
{
    [RoutePrefix("api/GroupReservation")]
    public class GroupReservationController : ezController
    {
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchInformation")]
        public async Task<IHttpActionResult> GetSearchInformation()
        {
            var user = Common.UserUtitily.getUserProfile();
            List<RoomTypes> roomTypes = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId).ToList();
            List<Source> source = context.Source.Where(s => s.HotelId == user.HotelId).ToList();
            List<Rooms> rooms = context.Rooms.Where(r => r.HotelId == user.HotelId).ToList();
            //List<RoomPrices> rates = context.RoomPrices.Where(rte => rte.HotelId == user.HotelId).ToList();
            return Ok(new
            {
                roomTypes,
                source,
                rooms
            });
        }
        public class SearchGroupReservationProcessModel
        {
            public string ReservationNumber { get; set; }
            public int? RoomTypeId { get; set; }
            public int? SourceId { get; set; }
            public int? Type { set; get; }
            public bool ArrivalIncluded { get; set; }
            public DateTime? ArrivalFrom { get; set; }
            public DateTime? ArrivalTo { get; set; }
            public DateTime? ReservationFrom { get; set; }
            public DateTime? ReservationTo { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchGroupReservationProcess")]
        public object SearchReservationProcess(SearchGroupReservationProcessModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var timeZoneOffset = -currentHotel.TimeZoneOffset / 60;
            TimeSpan offSet = new TimeSpan(timeZoneOffset, 0, 0);
            if (model.ArrivalIncluded == false)
            {
                model.ArrivalFrom = ((DateTime)SqlDateTime.MinValue).Date;
                model.ArrivalTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }else
            {
                if (model.ArrivalFrom == null)
                {
                    model.ArrivalFrom = ((DateTime)SqlDateTime.MinValue).Date;
                }
                else
                {
                    DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.ArrivalFrom).Year, ((DateTime)model.ArrivalFrom).Month, ((DateTime)model.ArrivalFrom).Day, ((DateTime)model.ArrivalFrom).Hour, ((DateTime)model.ArrivalFrom).Minute, ((DateTime)model.ArrivalFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                    DateTime from = (DateTime)fromTemp.Date;
                    from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                    model.ArrivalFrom = from;
                }

                if (model.ArrivalTo == null)
                {
                    model.ArrivalTo = ((DateTime)SqlDateTime.MaxValue).Date;
                }
                else
                {
                    DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.ArrivalTo).Year, ((DateTime)model.ArrivalTo).Month, ((DateTime)model.ArrivalTo).Day, ((DateTime)model.ArrivalTo).Hour, ((DateTime)model.ArrivalTo).Minute, ((DateTime)model.ArrivalTo).Second, offSet).ToOffset(TimeSpan.Zero);
                    DateTime to = (DateTime)toTemp.Date;
                    to = to.AddDays(1);
                    model.ArrivalTo = to;
                }
            }
            if (model.ReservationFrom == null)
            {
                model.ReservationFrom = ((DateTime)SqlDateTime.MinValue).Date;
            }
            else
            {
                DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.ReservationFrom).Year, ((DateTime)model.ReservationFrom).Month, ((DateTime)model.ReservationFrom).Day, ((DateTime)model.ReservationFrom).Hour, ((DateTime)model.ReservationFrom).Minute, ((DateTime)model.ReservationFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime from = (DateTime)fromTemp.Date;
                from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                model.ReservationFrom = from;
            }

            if (model.ReservationTo == null)
            {
                model.ReservationTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            else
            {
                DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.ReservationTo).Year, ((DateTime)model.ReservationTo).Month, ((DateTime)model.ReservationTo).Day, ((DateTime)model.ReservationTo).Hour, ((DateTime)model.ReservationTo).Minute, ((DateTime)model.ReservationTo).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime to = (DateTime)toTemp.Date;
                to = to.AddDays(1);
                model.ReservationTo = to;
            }
            //&& 
            var ListGroup = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.Reservations.IsGroup == true
               && (rr.Reservations.IsEmpty == null || rr.Reservations.IsEmpty == false)
               && rr.ArrivalDate >= model.ArrivalFrom && rr.ArrivalDate < model.ArrivalTo
               && (rr.BookingStatus == "BOOKED" || rr.BookingStatus == "CANCELLED")
               ).ToList();

            if (ListGroup.Count() > 0 && model.Type > 0)
            {
                if (model.Type == 1)
                {
                    //BOOKED
                    ListGroup = ListGroup.Where(rr => rr.BookingStatus == "BOOKED" ).ToList();
                }
                if (model.Type==2)
                {
                    //CANCELLED
                    ListGroup = ListGroup.Where(rr => rr.BookingStatus == "CANCELLED").ToList();
                }
            }
            //else if(ListGroup.Count() > 0 && model.Type == 0)
            //{
            //    ListGroup = ListGroup.Where(rr => (rr.BookingStatus == "BOOKED" || rr.BookingStatus == "CANCELLED")).ToList();
            //}
            if (ListGroup.Count > 0 && (model.ReservationFrom != null || model.ReservationTo != null))
            {
                ListGroup = ListGroup.Where(rr => rr.CreatedDate >= model.ReservationFrom && rr.CreatedDate < model.ReservationTo).ToList();
            }
            if (ListGroup.Count > 0 && model.ReservationNumber != null && model.ReservationNumber != "")
            {
                int ReservationNumberTemp = int.Parse(model.ReservationNumber);
                ListGroup = ListGroup.Where(rr => rr.Reservations.ReservationNumber == ReservationNumberTemp).ToList();
            }
            if (ListGroup.Count > 0 && model.RoomTypeId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.RoomTypeId == model.RoomTypeId).ToList();
            }
            if (ListGroup.Count > 0 && model.SourceId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.Reservations.SourceId == model.SourceId).ToList();
            }
            List<object> listGroupTmp = new List<object>();
            List<int> listReservationId = ListGroup.DistinctBy(d => d.Reservations.ReservationId).Select(s => s.Reservations.ReservationId).ToList();
            foreach (int ReservationId in listReservationId)
            {
                bool IsGroupCancel = false;
                var listReservations = context.ReservationRooms.Where(rr => rr.Reservations.ReservationId == ReservationId && rr.HotelId == user.HotelId).ToList();
                var minArrivalDate = listReservations.Where(rr => rr.ReservationId == ReservationId && rr.BookingStatus != "CANCELLED").Min(t => t.ArrivalDate);
                var maxDepartureDate = listReservations.Where(rr => rr.ReservationId == ReservationId && rr.BookingStatus != "CANCELLED").Max(t => t.DepartureDate);
                
                int CountCancel = listReservations.Where(lr => lr.BookingStatus == "CANCELLED").Count();
                if (listReservations.Count() == CountCancel)
                {
                    IsGroupCancel = true;
                    minArrivalDate = listReservations.Min(lr => lr.ArrivalDate);
                    maxDepartureDate = listReservations.Max(lr => lr.DepartureDate);
                }
                //
                var GroupName = listReservations.First().Reservations.GroupName;
                var CustomerLeader = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).Select(rr => new {
                    rr.ReservationId,
                    rr.ReservationRoomId,
                    rr.ReservationRoomNumber,
                    rr.Reservations.ReservationNumber,
                    rr.ArrivalDate,
                    rr.DepartureDate,
                    rr.Reservations,
                    rr.Travellers,
                    rr.Price,
                    rr.RoomTypes,
                    rr.Rooms,
                }).FirstOrDefault();
                var Source = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Source;
                var Company = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Company;
                var TotalReservation = listReservations.Where(rr => rr.BookingStatus!= "CANCELLED").Count();
                int children = listReservations.Where(rr => rr.BookingStatus != "CANCELLED").Sum(s => s.Child);
                int adults = listReservations.Where(rr => rr.BookingStatus != "CANCELLED").Sum(s => s.Adults);
                
                listGroupTmp.Add(new
                {
                    ReservationNumber = listReservations.First().Reservations.ReservationNumber,
                    ReservationId = ReservationId,
                    GroupName = GroupName,
                    CustomerLeader = CustomerLeader,
                    TotalReservation = TotalReservation,
                    Source = Source,
                    Company= Company,
                    TotalChildren = children,
                    TotalAdults = adults,
                    Color = CustomerLeader.Reservations.Color,
                    minArrivalDate,
                    maxDepartureDate,
                    IsGroupCancel
                });
            }
            return new {
                GroupReservationList= listGroupTmp
            };
        }
        public class SearchInhouseGroupProcessModel
        {
            public int? ReservationNumber { get; set; }
            public string GuestName { get; set; }
            //public string ReservationCode { get; set; }
            public int? RoomTypeId { get; set; }
            public int? RoomId { get; set; }
            public int? SourceId { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchInHouseGroupProcess")]
        public object SearchInHouseProcess(SearchInhouseGroupProcessModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var timeZoneOffset = -currentHotel.TimeZoneOffset / 60;
            TimeSpan offSet = new TimeSpan(timeZoneOffset, 0, 0);
            var ListGroup = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.Reservations.IsGroup == true
                && rr.BookingStatus == "CHECKIN" && (rr.Reservations.IsEmpty == null || rr.Reservations.IsEmpty == false)).ToList();

            if (ListGroup.Count > 0 && model.ReservationNumber > 0)
            {
                var reservationTemp = ListGroup.Where(rr => rr.Reservations.ReservationNumber == model.ReservationNumber).FirstOrDefault();
                ListGroup.Clear();
                if (reservationTemp != null)
                {
                    ListGroup.Add(reservationTemp);
                }
            }
            if (ListGroup.Count > 0 && model.RoomTypeId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.RoomTypeId == model.RoomTypeId).ToList();
            }
            if (ListGroup.Count > 0 && model.RoomId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.RoomId == model.RoomId && rr.RoomId!=null).ToList();
            }
            if (ListGroup.Count > 0 && model.SourceId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.Reservations.SourceId == model.SourceId).ToList();
            }
            if (ListGroup.Count > 0 && model.GuestName != "" && model.GuestName != null)
            {
                if (!Regex.IsMatch(model.GuestName, "^[a-zA-Z0-9]+$"))
                {
                    ListGroup = ListGroup.Where(rr => rr.Travellers.Fullname.ToLower().Contains(model.GuestName.ToLower())).ToList();
                }
                else
                {
                    Regex rgx = new Regex("[^a-zA-Z0-9 -]");
                    ListGroup = ListGroup.Where(rr => Regex.Replace(Utilities.convertToUnSign(rr.Travellers.Fullname).ToLower(), @"\s+", "").Contains(Regex.Replace(model.GuestName, @"\s+", "").ToLower())).ToList();
                }
            }

            //
            List<object> listGroupTmp = new List<object>();
            List<int> listReservationId = ListGroup.DistinctBy(d => d.Reservations.ReservationId).Select(s => s.Reservations.ReservationId).ToList();
            foreach (int ReservationId in listReservationId)
            {
                var minArrivalDate = ListGroup.Where(rr => rr.ReservationId == ReservationId).Min(t => t.ArrivalDate);
                var maxDepartureDate = ListGroup.Where(rr => rr.ReservationId == ReservationId).Max(t => t.DepartureDate);
                var listReservations = context.ReservationRooms.Where(rr => rr.Reservations.ReservationId == ReservationId && rr.HotelId == user.HotelId).ToList();
                //
                var GroupName = listReservations.First().Reservations.GroupName;
                var CustomerLeader = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).Select(rr => new {
                    rr.ReservationId,
                    rr.ReservationRoomId,
                    rr.ReservationRoomNumber,
                    rr.Reservations.ReservationNumber,
                    rr.ArrivalDate,
                    rr.DepartureDate,
                    rr.Reservations,
                    rr.Travellers,
                    rr.Price,
                    rr.RoomTypes,
                    rr.Rooms,
                }).FirstOrDefault();
                var Source = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Source;
                var Company = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Company;
                var TotalReservation = listReservations.Where(rr => rr.BookingStatus != "CANCELLED").Count();
                int children = listReservations.Where(rr => rr.BookingStatus != "CANCELLED").Sum(s => s.Child);
                int adults = listReservations.Where(rr => rr.BookingStatus != "CANCELLED").Sum(s => s.Adults);

                listGroupTmp.Add(new
                {
                    ReservationNumber = listReservations.First().Reservations.ReservationNumber,
                    ReservationId = ReservationId,
                    GroupName = GroupName,
                    CustomerLeader = CustomerLeader,
                    TotalReservation = TotalReservation,
                    Source = Source,
                    Company= Company,
                    TotalChildren = children,
                    TotalAdults = adults,
                    Color = CustomerLeader.Reservations.Color,
                    minArrivalDate,
                    maxDepartureDate
                });
            }
            return new
            {
                GroupInhouseList = listGroupTmp
            };
        }
        public class SearchDepartedGroupProcessModel
        {
            public int? ReservationNumber { get; set; }
            public string GuestName { get; set; }
            public int? SourceId { get; set; }
            public int? RoomTypeId { get; set; }
            public int? RoomId { get; set; }
            public DateTime? From { get; set; }
            public DateTime? To { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchDepartedGroupProcess")]
        public object SearchDepartedProcess(SearchDepartedGroupProcessModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var timeZoneOffset = -currentHotel.TimeZoneOffset / 60;
            TimeSpan offSet = new TimeSpan(timeZoneOffset, 0, 0);
            if (model.From == null)
            {
                model.From = ((DateTime)SqlDateTime.MinValue).Date;
            }
            else
            {
                DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.From).Year, ((DateTime)model.From).Month, ((DateTime)model.From).Day, ((DateTime)model.From).Hour, ((DateTime)model.From).Minute, ((DateTime)model.From).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime from = (DateTime)fromTemp.Date;
                from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                model.From = from;
            }

            if (model.To == null)
            {
                model.To = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            else
            {
                DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.To).Year, ((DateTime)model.To).Month, ((DateTime)model.To).Day, ((DateTime)model.To).Hour, ((DateTime)model.To).Minute, ((DateTime)model.To).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime to = (DateTime)toTemp.Date;
                to = to.AddDays(1);
                model.To = to;
            }
            var ListGroup = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.Reservations.IsGroup == true
                && (rr.BookingStatus == "CHECKOUT") && (rr.Reservations.IsEmpty == null || rr.Reservations.IsEmpty == false)
                && rr.DepartureDate >= model.From && rr.DepartureDate <= model.To).ToList();

            if (ListGroup.Count > 0 && model.ReservationNumber > 0)
            {
                var reservationTemp = ListGroup.Where(rr => rr.Reservations.ReservationNumber == model.ReservationNumber).FirstOrDefault();
                ListGroup.Clear();
                if (reservationTemp != null)
                {
                    ListGroup.Add(reservationTemp);
                }
            }

            if (ListGroup.Count > 0 && model.GuestName != "" && model.GuestName != null)
            {
                if (!Regex.IsMatch(model.GuestName, "^[a-zA-Z0-9]+$"))
                {
                    ListGroup = ListGroup.Where(rr => rr.Travellers.Fullname.ToLower().Contains(model.GuestName.ToLower())).ToList();
                }
                else
                {
                    Regex rgx = new Regex("[^a-zA-Z0-9 -]");
                    ListGroup = ListGroup.Where(rr => Regex.Replace(Utilities.convertToUnSign(rr.Travellers.Fullname).ToLower(), @"\s+", "").Contains(Regex.Replace(model.GuestName, @"\s+", "").ToLower())).ToList();
                }
            }

            if (ListGroup.Count > 0 && model.SourceId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.Reservations.SourceId == model.SourceId).ToList();
            }
            if (ListGroup.Count > 0 && model.RoomTypeId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.RoomTypeId == model.RoomTypeId).ToList();
            }

            if (ListGroup.Count > 0 && model.RoomId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.RoomId == model.RoomId && rr.RoomId != null).ToList();
            }

            //
            List<object> listGroupTmp = new List<object>();
            List<int> listReservationId = ListGroup.DistinctBy(d => d.Reservations.ReservationId).Select(s => s.Reservations.ReservationId).ToList();
            foreach (int ReservationId in listReservationId)
            {
                var minArrivalDate = ListGroup.Where(rr => rr.ReservationId == ReservationId).Min(t => t.ArrivalDate);
                var maxDepartureDate = ListGroup.Where(rr => rr.ReservationId == ReservationId).Max(t => t.DepartureDate);
                var listReservations = context.ReservationRooms.Where(rr => rr.Reservations.ReservationId == ReservationId && rr.HotelId == user.HotelId).ToList();
                var checkStatus = listReservations.Where(lr => (lr.BookingStatus == "CHECKIN" || lr.BookingStatus == "BOOKED")).ToList();
                if (checkStatus.Count() == 0)
                {
                    var GroupName = listReservations.First().Reservations.GroupName;
                    var CustomerLeader = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).Select(rr => new {
                        rr.ReservationId,
                        rr.ReservationRoomId,
                        rr.ReservationRoomNumber,
                        rr.Reservations.ReservationNumber,
                        rr.ArrivalDate,
                        rr.DepartureDate,
                        rr.Reservations,
                        rr.Travellers,
                        rr.Price,
                        rr.RoomTypes,
                        rr.Rooms,
                    }).FirstOrDefault();
                    var Source = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Source;
                    var Company = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Company;
                    var TotalReservation = listReservations.Where(rr => rr.BookingStatus != "CANCEL").Count();
                    int children = listReservations.Sum(s => s.Child);
                    int adults = listReservations.Sum(s => s.Adults);

                    listGroupTmp.Add(new
                    {
                        ReservationNumber = listReservations.First().Reservations.ReservationNumber,
                        ReservationId = ReservationId,
                        GroupName = GroupName,
                        CustomerLeader = CustomerLeader,
                        TotalReservation = TotalReservation,
                        Source = Source,
                        Company= Company,
                        TotalChildren = children,
                        TotalAdults = adults,
                        Color = CustomerLeader.Reservations.Color,
                        minArrivalDate,
                        maxDepartureDate
                    });
                }
            }
            return new
            {
                GroupDepartedList = listGroupTmp
            };
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchMergeGroupProcess")]
        public object SearchMergeGroupProcess(SearchGroupReservationProcessModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var timeZoneOffset = -currentHotel.TimeZoneOffset / 60;
            TimeSpan offSet = new TimeSpan(timeZoneOffset, 0, 0);
            if (model.ArrivalIncluded == false)
            {
                model.ArrivalFrom = ((DateTime)SqlDateTime.MinValue).Date;
                model.ArrivalTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            else
            {
                if (model.ArrivalFrom == null)
                {
                    model.ArrivalFrom = ((DateTime)SqlDateTime.MinValue).Date;
                }
                else
                {
                    DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.ArrivalFrom).Year, ((DateTime)model.ArrivalFrom).Month, ((DateTime)model.ArrivalFrom).Day, ((DateTime)model.ArrivalFrom).Hour, ((DateTime)model.ArrivalFrom).Minute, ((DateTime)model.ArrivalFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                    DateTime from = (DateTime)fromTemp.Date;
                    from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                    model.ArrivalFrom = from;
                }

                if (model.ArrivalTo == null)
                {
                    model.ArrivalTo = ((DateTime)SqlDateTime.MaxValue).Date;
                }
                else
                {
                    DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.ArrivalTo).Year, ((DateTime)model.ArrivalTo).Month, ((DateTime)model.ArrivalTo).Day, ((DateTime)model.ArrivalTo).Hour, ((DateTime)model.ArrivalTo).Minute, ((DateTime)model.ArrivalTo).Second, offSet).ToOffset(TimeSpan.Zero);
                    DateTime to = (DateTime)toTemp.Date;
                    to = to.AddDays(1);
                    model.ArrivalTo = to;
                }
            }
            if (model.ReservationFrom == null)
            {
                model.ReservationFrom = ((DateTime)SqlDateTime.MinValue).Date;
            }
            else
            {
                DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.ReservationFrom).Year, ((DateTime)model.ReservationFrom).Month, ((DateTime)model.ReservationFrom).Day, ((DateTime)model.ReservationFrom).Hour, ((DateTime)model.ReservationFrom).Minute, ((DateTime)model.ReservationFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime from = (DateTime)fromTemp.Date;
                from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                model.ReservationFrom = from;
            }

            if (model.ReservationTo == null)
            {
                model.ReservationTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            else
            {
                DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.ReservationTo).Year, ((DateTime)model.ReservationTo).Month, ((DateTime)model.ReservationTo).Day, ((DateTime)model.ReservationTo).Hour, ((DateTime)model.ReservationTo).Minute, ((DateTime)model.ReservationTo).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime to = (DateTime)toTemp.Date;
                to = to.AddDays(1);
                model.ReservationTo = to;
            }
            //&& 
            var ListGroup = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.Reservations.IsGroup == true
                && (rr.BookingStatus == "CHECKIN" || rr.BookingStatus == "BOOKED")
                && (rr.Reservations.IsEmpty == null || rr.Reservations.IsEmpty == false)
                && rr.ArrivalDate >= model.ArrivalFrom && rr.ArrivalDate < model.ArrivalTo).ToList();

            if (ListGroup.Count > 0 && (model.ReservationFrom != null || model.ReservationTo != null))
            {
                ListGroup = ListGroup.Where(rr => rr.CreatedDate >= model.ReservationFrom && rr.CreatedDate < model.ReservationTo).ToList();
            }
            if (ListGroup.Count > 0 && model.ReservationNumber != null && model.ReservationNumber != "")
            {
                var ListResNo = model.ReservationNumber.Split(',');
                if (ListResNo.Length > 0)
                {
                    List<ReservationRooms> ListRR = new List<ReservationRooms>();
                    foreach (string tmp in ListResNo)
                    {
                        int ReservationNumber = 0;
                        bool result = Int32.TryParse(tmp, out ReservationNumber);
                        if (result)
                        {
                            var RR = ListGroup.Where(rr => rr.Reservations.ReservationNumber == ReservationNumber).FirstOrDefault();
                            if (RR != null)
                                ListRR.Add(RR);
                        }
                    }
                    ListGroup.Clear();
                    ListGroup = ListRR;
                }
            }
            if (ListGroup.Count > 0 && model.RoomTypeId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.RoomTypeId == model.RoomTypeId).ToList();
            }
            if (ListGroup.Count > 0 && model.SourceId > 0)
            {
                ListGroup = ListGroup.Where(rr => rr.Reservations.SourceId == model.SourceId).ToList();
            }
            List<object> listGroupTmp = new List<object>();
            List<int> listReservationId = ListGroup.DistinctBy(d => d.Reservations.ReservationId).Select(s => s.Reservations.ReservationId).ToList();
            foreach (int ReservationId in listReservationId)
            {
                var minArrivalDate = context.ReservationRooms.Where(rr => rr.ReservationId == ReservationId).Min(t => t.ArrivalDate);
                var maxDepartureDate = context.ReservationRooms.Where(rr => rr.ReservationId == ReservationId).Max(t => t.DepartureDate);
                var listReservations = context.ReservationRooms.Where(rr => rr.Reservations.ReservationId == ReservationId && rr.HotelId == user.HotelId).ToList();
                //
                var GroupName = listReservations.First().Reservations.GroupName;
                var CustomerLeader = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).Select(rr => new {
                    rr.ReservationId,
                    rr.ReservationRoomId,
                    rr.ReservationRoomNumber,
                    rr.Reservations.ReservationNumber,
                    rr.ArrivalDate,
                    rr.DepartureDate,
                    rr.Reservations,
                    rr.Travellers,
                    rr.Price,
                    rr.RoomTypes,
                    rr.Rooms,
                }).FirstOrDefault();
                var Source = listReservations.Where(lr => lr.IsGroupMaster != null && lr.IsGroupMaster == true).FirstOrDefault().Reservations.Source;
                var TotalReservation = listReservations.Where(rr => rr.BookingStatus != "CANCEL").Count();
                int children = listReservations.Sum(s => s.Child);
                int adults = listReservations.Sum(s => s.Adults);

                listGroupTmp.Add(new
                {
                    ReservationNumber = listReservations.First().Reservations.ReservationNumber,
                    ReservationId = ReservationId,
                    GroupName = GroupName,
                    CustomerLeader = CustomerLeader,
                    TotalReservation = TotalReservation,
                    Source = Source,
                    TotalChildren = children,
                    TotalAdults = adults,
                    Color = CustomerLeader.Reservations.Color,
                    minArrivalDate,
                    maxDepartureDate
                });
            }
            return new
            {
                GroupReservationList = listGroupTmp
            };
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchReservationProcess")]
        public object SearchReservationProcess(SearchReservationProcessModel model)
        {

            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            var timeZoneOffset = -currentHotel.TimeZoneOffset / 60;
            TimeSpan offSet = new TimeSpan(timeZoneOffset, 0, 0);

            if (model.ArrivalIncluded == false)
            {
                model.ArrivalFrom = ((DateTime)SqlDateTime.MinValue).Date;
                model.ArrivalTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            else
            {
                if (model.ArrivalFrom == null)
                {
                    model.ArrivalFrom = ((DateTime)SqlDateTime.MinValue).Date;
                }
                else
                {
                    DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.ArrivalFrom).Year, ((DateTime)model.ArrivalFrom).Month, ((DateTime)model.ArrivalFrom).Day, ((DateTime)model.ArrivalFrom).Hour, ((DateTime)model.ArrivalFrom).Minute, ((DateTime)model.ArrivalFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                    //model.ReservationFrom = fromTemp.Date;
                    DateTime from = (DateTime)fromTemp.Date;
                    from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                    model.ArrivalFrom = from;
                }

                if (model.ArrivalTo == null)
                {
                    model.ArrivalTo = ((DateTime)SqlDateTime.MaxValue).Date;
                }
                else
                {
                    DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.ArrivalTo).Year, ((DateTime)model.ArrivalTo).Month, ((DateTime)model.ArrivalTo).Day, ((DateTime)model.ArrivalTo).Hour, ((DateTime)model.ArrivalTo).Minute, ((DateTime)model.ArrivalTo).Second, offSet).ToOffset(TimeSpan.Zero);
                    DateTime to = (DateTime)toTemp.Date;
                    to = to.AddDays(1);
                    model.ArrivalTo = to;
                }
            }
            if (model.ReservationFrom == null)
            {
                model.ReservationFrom = ((DateTime)SqlDateTime.MinValue).Date;
            }
            else
            {
                DateTimeOffset fromTemp = new DateTimeOffset(((DateTime)model.ReservationFrom).Year, ((DateTime)model.ReservationFrom).Month, ((DateTime)model.ReservationFrom).Day, ((DateTime)model.ReservationFrom).Hour, ((DateTime)model.ReservationFrom).Minute, ((DateTime)model.ReservationFrom).Second, offSet).ToOffset(TimeSpan.Zero);
                //model.ReservationFrom = fromTemp.Date;
                DateTime from = (DateTime)fromTemp.Date;
                from = from.AddMinutes(-currentHotel.TimeZoneOffset);
                model.ReservationFrom = from;
            }

            if (model.ReservationTo == null)
            {
                model.ReservationTo = ((DateTime)SqlDateTime.MaxValue).Date;
            }
            else
            {
                DateTimeOffset toTemp = new DateTimeOffset(((DateTime)model.ReservationTo).Year, ((DateTime)model.ReservationTo).Month, ((DateTime)model.ReservationTo).Day, ((DateTime)model.ReservationTo).Hour, ((DateTime)model.ReservationTo).Minute, ((DateTime)model.ReservationTo).Second, offSet).ToOffset(TimeSpan.Zero);
                DateTime to = (DateTime)toTemp.Date;
                to = to.AddDays(1);
                model.ReservationTo = to;
            }
            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ArrivalDate >= model.ArrivalFrom && rr.ArrivalDate < model.ArrivalTo  && rr.BookingStatus != "CANCELLED" && ( rr.Reservations.IsGroup == null || rr.Reservations.IsGroup.Value == false ) && ( rr.Reservations.IsEmpty == null || rr.Reservations.IsEmpty == false )) 
                .Select(rr => new
                {
                    rr.BookingStatus,
                    rr.Adults,
                    rr.Child,
                    rr.ArrivalDate,
                    rr.DepartureDate,
                    rr.Rooms,
                    rr.Reservations,
                    Travellers = new
                    {
                        rr.Travellers.TravellerId,
                        rr.Travellers.Fullname
                    },
                    rr.RoomPrices,
                    rr.RoomTypes,
                    rr.RoomId,
                    rr.RoomTypeId,
                    rr.ReservationRoomId,
                    rr.ReservationId,
                    rr.TravellersList,
                    rr.CancelReason,
                    rr.Foc,
                    rr.DiscountPercentage,
                    rr.DiscountFlat,
                    rr.RoomPriceId,
                    rr.Note,
                    rr.CreatedDate
                }).ToList();

            if (reservationRooms.Count > 0 && (model.ReservationFrom != null || model.ReservationTo != null))
            {
                reservationRooms = reservationRooms.Where(rr => rr.CreatedDate >= model.ReservationFrom && rr.CreatedDate < model.ReservationTo).ToList();
            }

            if (reservationRooms.Count > 0 && model.ReservationRoomId > 0)
            {
                var reservationTemp = reservationRooms.Where(rr => rr.Reservations.ReservationNumber == model.ReservationRoomId).FirstOrDefault();
                reservationRooms.Clear();
                if (reservationTemp != null)
                {
                    reservationRooms.Add(reservationTemp);
                }
            }

            if (reservationRooms.Count > 0 && model.RoomTypeId > 0)
            {
                reservationRooms = reservationRooms.Where(rr => rr.RoomTypeId == model.RoomTypeId).ToList();
            }

            if (reservationRooms.Count > 0 && model.RoomId > 0)
            {
                reservationRooms = reservationRooms.Where(rr => rr.RoomId == model.RoomId).ToList();
            }
            if (reservationRooms.Count > 0 && model.Type > 0)
            {
                var status = "";
                switch (model.Type)
                {
                    case 1:
                        status = "BOOKED";
                        break;
                    case 2:
                        status = "NOSHOW";
                        break;
                    case 3:
                        status = "CANCELLED";
                        break;
                    case 4:
                        status = "CHECKIN";
                        break;

                }
                if (status == "NOSHOW")
                {
                    reservationRooms = reservationRooms.Where(rr => rr.BookingStatus == "BOOKED" && rr.ArrivalDate < DateTime.UtcNow).ToList();
                }
                else
                {
                    reservationRooms = reservationRooms.Where(rr => rr.BookingStatus == status).ToList();
                }

            }

            if (reservationRooms.Count > 0 && model.GuestName != null)
            {
                if (!Regex.IsMatch(model.GuestName, "^[a-zA-Z0-9]+$"))
                {
                    reservationRooms = reservationRooms.Where(rr => rr.Travellers.Fullname.ToLower().Contains(model.GuestName.ToLower())).ToList();
                }
                else
                {
                    Regex rgx = new Regex("[^a-zA-Z0-9 -]");
                    reservationRooms = reservationRooms.Where(rr => Regex.Replace(Utilities.convertToUnSign(rr.Travellers.Fullname).ToLower(), @"\s+", "").Contains(Regex.Replace(model.GuestName, @"\s+", "").ToLower())).ToList();
                }
            }

            var statusColors = context.StatusColors.Where(sc => sc.HotelId == user.HotelId).ToList();

            return new
            {
                reservationRooms = reservationRooms,
                statusColors = statusColors
            };
        }

        public class SearchGroupModel
        {
            public DateTime from { get; set; }
            public DateTime to { get; set; }
        }
        public class AvailabilityByRoomType
        {
            public DateTime Dates { get; set; }
            public int AvailableRooms { get; set; }
            public int RoomTypeId { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SearchAvailabilityGroup")]
        public IHttpActionResult SearchAvailabilityGroup(SearchGroupModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);

            model.from = model.from.AddMinutes(-currentHotel.TimeZoneOffset);
            model.to = model.to.AddMinutes(-currentHotel.TimeZoneOffset);
            //var RoomAvailability = Utilities.GetRoomAvailabilityMatrix(model.from, model.to);
            var RoomAvailabilityTMP = context.RoomTypeCheckAvailability(user.HotelId, model.from, model.to);
            //IEnumerable<AvailabilityByRoomType> RoomAvailabilityTMP = context.RoomTypeCheckAvailability(user.HotelId, model.from, model.to).GetResult<AvailabilityByRoomType>(); // result.GetResult<Employee>();

            List<AvailabilityByRoomType> RoomAvailability = new List<AvailabilityByRoomType>();
            foreach (var item in RoomAvailabilityTMP)
            {
                AvailabilityByRoomType obj = new AvailabilityByRoomType();
                obj.Dates = (DateTime)item.Dates;
                obj.AvailableRooms = (int)item.AvailableRooms;
                obj.RoomTypeId = (int)item.RoomTypeId;
                RoomAvailability.Add(obj);
            }
            var RoomType = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId && rt.IsDeleted == false && rt.IsHidden == false).Select( rt => new {
                rt.RoomTypeId,
                rt.RoomTypeName,
                rt.RoomTypeDescription,
                rt.Price,
                rt.RoomTypeCode,
                rt.DefaultAdults,
                rt.DefaultChilds,
                rt.RoomPricesList
            }).ToList();
            return Ok(new
            {
                RoomAvailability,
                RoomType
            });
        }
        public class MergeGroupModel
        {
            public int NewReservationId { set; get; }
            public List<int> ListReservationId { set; get; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessMergeGroup")]
        public async Task<IHttpActionResult> MergeGroup(MergeGroupModel model)
        {
           
            var user = Common.UserUtitily.getUserProfile();
            var NewGroup = context.Reservations.Where(r => r.HotelId==user.HotelId && r.ReservationId == model.NewReservationId && (r.IsEmpty == null || r.IsEmpty == false)).FirstOrDefault();
            if (NewGroup == null)
                return BadRequest("GROUP IS NOT EXISTS");
            if (model.ListReservationId.Count() == 0)
                return BadRequest("LIST GROUP MERGE IS NULL");
            var oldReservation = context.Reservations.Where(r => model.ListReservationId.Contains(r.ReservationId)).ToList();
            var oldRR = context.ReservationRooms.Where(rr => model.ListReservationId.Contains(rr.ReservationId.Value)).ToList();

            foreach (var reservation in oldReservation)
            {
                reservation.IsEmpty = true;
            }
            //
            foreach (var rr in oldRR)
            {
                rr.IsGroupMaster = false;
                rr.ReservationId = NewGroup.ReservationId;
            }
            context.SubmitChanges();
            MemoryCacher.ClearStatusCache(user.HotelId);
            return Ok(NewGroup.ReservationId);
        }
        public class BalanceDueInfo
        {
            public int ReservationRoomId { get; set; }
            public decimal Total { get; set; }
            public decimal Paid { get; set; }
            public decimal Balance { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetGroupInformation")]
        public async Task<IHttpActionResult> GetGroupInfo()
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.Where(ht => ht.HotelId == user.HotelId).FirstOrDefault();
            List<Rooms> rooms = context.Rooms.Where(r => r.HotelId == user.HotelId).ToList();
            List<RoomTypes> roomTypes = context.RoomTypes.Where(rt => rt.HotelId == user.HotelId && rt.IsDeleted == false && rt.IsHidden == false).ToList();
            
            List<Source> source = context.Source.Where(s => s.HotelId == user.HotelId).ToList();
            List<Market> markets = context.Market.Where(m => m.HotelId == user.HotelId).ToList();
            List<Company> companys = context.Company.Where(c => c.HotelId == user.HotelId).ToList();

            List<Travellers> travellers = context.Travellers.Where(tvl => tvl.HotelId == user.HotelId).ToList();
            List<Countries> countries = context.Countries.ToList();
            var paymentMethods = context.PaymentMethods.ToList();
            if (paymentMethods.Count == 0)
            {
                //Auto generate payment methods
                var cash = new PaymentMethods();
                cash.PaymentMethodName = "CASH";
                cash.PaymentMethodDescription = "CASH_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(cash);
                var credit = new PaymentMethods();
                credit.PaymentMethodName = "CREDIT";
                credit.PaymentMethodDescription = "CREDIT_PAYMENT";
                context.PaymentMethods.InsertOnSubmit(credit);
                var banktransfer = new PaymentMethods();
                banktransfer.PaymentMethodName = "BANK_TRANSFER";
                banktransfer.PaymentMethodDescription = "BANK_TRANSFER";
                context.PaymentMethods.InsertOnSubmit(banktransfer);
                var cityledger = new PaymentMethods();
                cityledger.PaymentMethodName = "CITY_LEDGER";
                cityledger.PaymentMethodDescription = "CITY_LEDGER";
                context.PaymentMethods.InsertOnSubmit(cityledger);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
            }
            //
            var currencies = context.Money.Where(curr => curr.HotelId == user.HotelId).ToList();
            var defaultCurrency = currencies.Where(cur => cur.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault();
            if (defaultCurrency == null)
            {
                defaultCurrency = currencies.Where(cur => cur.MoneyName == "VND").FirstOrDefault();
            }
            if (currencies.Count == 0)
            {
                Money defaultMoney = new Money();
                defaultMoney.HotelId = user.HotelId;
                defaultMoney.MoneyName = "VND";
                defaultMoney.ExchangeRate = 1.0;
                context.Money.InsertOnSubmit(defaultMoney);
                context.SubmitChanges();
                Common.Elastic.IndexLastAudit(context);
                currentHotel.DefaultMoneyId = defaultMoney.MoneyId;
            }
            var currenciesISO = new List<Currencies>();
            foreach (var currency in currencies)
            {
                var iso = context.Currencies.Where(curr => curr.CurrencyId == currency.CurrencyId).FirstOrDefault();
                if (iso != null)
                {
                    currenciesISO.Add(iso);
                }
            }
            return Ok(new {
                roomTypes,
                source,
                markets,
                companys,
                travellers,
                countries,
                paymentMethods,
                currenciesISO,
                currencies,
                defaultCurrency = new
                {
                    MoneyId = defaultCurrency.MoneyId,
                    MoneyName = defaultCurrency.MoneyName,
                    CurrencyInfo = defaultCurrency.Currencies
                },
            });
        }

        public class AddNewGroupModel
        {
            public Reservations Reservation { get; set; }
            public List<ReservationRooms> ReservationRooms { get; set; }
            public List<Payments> Payments { get; set; }
            //public Travellers Traveller { get; set; }
            public Market Market { get; set; }
            public Company Company { get; set; }
            public Source Source { get; set; }
            public List<int> IsBreakfast { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAddNewGroup")]
        public IHttpActionResult ProcessAddNewGroup(AddNewGroupModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null)
            {
                // Market
                if (model.Market != null)
                {
                    if (model.Market.MarketId == 0)
                    {
                        model.Market.Hotels = currentHotel;
                        model.Market.CreatedDate = DateTime.UtcNow;
                        model.Market.CreatedUserId = user.UserId;
                        context.Market.InsertOnSubmit(model.Market);
                        model.Reservation.Market = model.Market;
                    }
                    else
                    {
                        model.Reservation.MarketId = model.Market.MarketId;
                    }
                }
                

                // Source
                if (model.Source != null)
                {
                    if (model.Source.SourceId == 0)
                    {
                        model.Source.Hotels = currentHotel;
                        model.Source.CreatedDate = DateTime.UtcNow;
                        model.Source.CreatedUserId = user.UserId;
                        context.Source.InsertOnSubmit(model.Source);
                        model.Reservation.Source = model.Source;
                    }
                    else
                    {
                        model.Reservation.SourceId = model.Source.SourceId;
                    }
                    
                }

                // Company
                if (model.Company != null)
                {
                    if (model.Company.CompanyId == 0)
                    {
                        model.Company.Hotels = currentHotel;
                        model.Company.CreatedDate = DateTime.UtcNow;
                        model.Company.CreatedUserId = user.UserId;
                        //model.Company.Source = model.Source != null ? model.Source : null;
                        context.Company.InsertOnSubmit(model.Company);
                        model.Reservation.Company = model.Company;
                    }
                    else
                    {
                        model.Reservation.CompanyId = model.Company.CompanyId;
                    }
                    
                }
                

                // Reservations
                model.Reservation.Hotels = currentHotel;
                model.Reservation.CreatedDate = DateTime.UtcNow;
                model.Reservation.CreatedUserId = user.UserId;
                model.Reservation.ReservationNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATION");
                model.Reservation.IsGroup = true;

                string leaderTraveller = "";
                // ReservationRooms
                if (model.ReservationRooms.Count > 0)
                {
                    foreach(var rr in model.ReservationRooms)
                    {
                        // Traveller
                        if (rr.Travellers != null)
                        {
                            if (rr.IsGroupMaster == true) leaderTraveller = rr.Travellers.Fullname;

                            rr.Travellers.HotelId = user.HotelId;
                            if (rr.Travellers.TravellerId == 0)
                            {
                                rr.Travellers.Hotels = currentHotel;
                                rr.Travellers.CreatedDate = DateTime.UtcNow;
                                rr.Travellers.CreatedUserId = user.UserId;
                                context.Travellers.InsertOnSubmit(rr.Travellers);
                            }

                            ReservationTravellers resTraveller = new ReservationTravellers();
                            resTraveller.ReservationRooms = rr;
                            resTraveller.Travellers = rr.Travellers;
                            context.ReservationTravellers.InsertOnSubmit(resTraveller);

                            ReservationTravellerExtraInformation newRTEI = new ReservationTravellerExtraInformation();
                            newRTEI.HotelId = user.HotelId;
                            newRTEI.ReservationTravellers = resTraveller;
                            newRTEI.IsChild = false;
                            context.ReservationTravellerExtraInformation.InsertOnSubmit(newRTEI);
                        }
                        
                        rr.Hotels = currentHotel;
                        rr.Reservations = model.Reservation;
                        rr.CreatedDate = DateTime.UtcNow;
                        rr.CreatedUserId = user.UserId;
                        rr.BookingStatus = "BOOKED";
                        rr.ReservationRoomNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATIONROOM");
                        var isBreakfast = true;
                        if (rr.RoomBreakfastList.Count > 0)
                        {
                            isBreakfast = (bool)rr.RoomBreakfastList[0].IsBreakfast;
                        }
                        rr.RoomBreakfastList = null;
                        context.ReservationRooms.InsertOnSubmit(rr);
                        var dateRange = new DateRange(rr.ArrivalDate.Value, rr.DepartureDate.Value);
                        if (isBreakfast)
                        {
                            ReservationUtility.CreateRoomBreakfasts(dateRange, rr, user, context);
                        }
                        ReservationUtility.CreateRoomCharges(dateRange, rr, user, context);
                        
                    }
                }
                Notification.processNotificationBookedGroup(user, model.Reservation.ReservationNumber, leaderTraveller, model.ReservationRooms.Count, model.languageKeys["NOTIFICATION_BOOKED_GROUP_CONTENT"].ToString());

                // Payments
                if (model.Payments != null && model.Payments.Count > 0)
                {
                    var leaderRR = model.ReservationRooms.Where(rr => rr.IsGroupMaster == true).FirstOrDefault();
                    if (leaderRR != null)
                    {
                        foreach(var payment in model.Payments)
                        {
                            payment.Hotels = currentHotel;
                            payment.ReservationRooms = leaderRR;
                            payment.CreatedDate = DateTime.UtcNow;
                            payment.CreatedUserId = user.UserId;
                            payment.PaymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "PAYMENT");
                            context.Payments.InsertOnSubmit(payment);
                            
                        }
                    }
                }

                context.SubmitChanges();

               

                // Consider only if hotel is using module "Channel Mananger"
                // Room Available

                foreach (var rr in model.ReservationRooms)
                {
                    ReservationUtility.RebuildAvailableRoom(rr, user, context);

                }
                //Send notification
                if (model.Payments != null && model.Payments.Count > 0)
                {

                    foreach (var payment in model.Payments)
                    {

                        PaymentModel paymentsModel = new PaymentModel();
                        paymentsModel.languageKeys = model.languageKeys;
                        paymentsModel.payment = payment;
                        Notification.processNotificationAddNewPayment(paymentsModel, user);
                    }

                }


                Elastic.IndexLastAudit(context);
                return Ok(model.Reservation.ReservationId);
            }
            return Ok(BadRequest("HOTEL_DOES_NOT_EXIST"));

        }

        public class ReservationRoomInfo
        {
            public ReservationRooms ReservationRooms { get; set; }
            public string RoomName { get; set; }
            public string TravellerName { get; set; }
        }

        public class PaymentGroupInfo
        {
            public int PaymentId { get; set; }
            public string PaymentGroupNumber { get; set; }
            public string RoomName { get; set; }
            public decimal Amount { get; set; }
            public DateTime PaymentGroupCreatedDate { get; set; }
            public string PaymentGroupCreatedUser { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("GetGroupReservationDetail")]
        public async Task<IHttpActionResult> GetGroupReservationDetail(int reservationId)
        {
            var user = Common.UserUtitily.getUserProfile();
            var groupBalanceDueInfo = new List<BalanceDueInfo>();
            var reservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == reservationId && r.IsGroup == true);
            if (reservation != null)
            {
                object groupLeader = null;
                var reservationRoomList = new List<object>();
                var reservationRooms = reservation.ReservationRoomsList;
                var paymentList = new List<Payments>();
                var paymentUser = new List<object>();
                var isReservationBreakfast = false;
                var isGroupCheckOut = !reservation.ReservationRoomsList.Any(rr => rr.BookingStatus != "CHECKOUT");
                if (reservationRooms != null && reservationRooms.Count > 0)
                {
                    foreach (var RR in reservationRooms)
                    {
                        // Group Leader
                        if (RR.IsGroupMaster == true)
                        {
                            groupLeader = new
                            {
                                RR.Travellers.Address,
                                RR.Travellers.Countries,
                                RR.Travellers.CountryId,
                                RR.Travellers.Email,
                                RR.Travellers.Fullname,
                                RR.Travellers.Gender,
                                RR.Travellers.HotelId,
                                RR.Travellers.IdentityNumber,
                                RR.Travellers.Mobile,
                                RR.Travellers.Note,
                                RR.Travellers.TravellerId,
                                RR.Travellers.Birthday,
                            };
                        }
                        var balanceTemp = new BalanceDueInfo();
                        balanceTemp.ReservationRoomId = RR.ReservationRoomId;
                        if (RR.BookingStatus == "CHECKIN" || RR.BookingStatus == "BOOKED")
                        {
                            CalculateRoomPrice calculateRoomPrice = new CalculateRoomPrice();
                            calculateRoomPrice.roomId = RR.RoomId ?? 0;
                            calculateRoomPrice.reservationRoomId = RR.ReservationRoomId;
                            calculateRoomPrice.arrivalDate = RR.ArrivalDate ?? default(DateTime);
                            calculateRoomPrice.departureDate = RR.DepartureDate ?? default(DateTime);
                            calculateRoomPrice.adults = RR.Adults;
                            calculateRoomPrice.children = RR.Child;
                            calculateRoomPrice.RoomPriceId = RR.RoomPriceId;
                            calculateRoomPrice.FOC = RR.Foc;
                            calculateRoomPrice.DiscountFlat = RR.DiscountFlat;
                            calculateRoomPrice.DiscountPercentage = (float)RR.DiscountPercentage;
                            calculateRoomPrice.languageKeys = null;
                            calculateRoomPrice.Price = RR.Price;
                            calculateRoomPrice.roomTypeId = (int)RR.RoomTypeId;
                            // Total
                            var roomExtraServiceTotal = RR.RoomExtraServicesList.Where(e=>e.IsDeleted==false).Sum(es => es.Amount*es.Quantity);
                            //var roomExtraServiceItemTotal = RR.RoomExtraServiceItemsList.Where(e => e.IsDeleted == false).Sum(es => es.Price * es.Quantity);
                            balanceTemp.Total = (decimal)roomExtraServiceTotal; //+(decimal)roomExtraServiceItemTotal;
                            var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(calculateRoomPrice);
                            if (planListDateRange != null)
                            {
                                balanceTemp.Total += planListDateRange.totalPrice;
                            }
                        }
                        else if (RR.BookingStatus == "CHECKOUT")
                        {
                            balanceTemp.Total = (decimal)RR.ReportItemsList.Sum(r => r.ItemTotal);
                        }

                        // Paid
                        var payments = RR.PaymentsList.Sum(p => p.Amount);
                        balanceTemp.Paid = (decimal)payments;

                        // Balance
                        balanceTemp.Balance = balanceTemp.Total - balanceTemp.Paid;
                        groupBalanceDueInfo.Add(balanceTemp);

                        // Payment
                        var payment = RR.PaymentsList.Where(p => p.IsPaymentGroup == true);
                        if (payment != null)
                        {
                            paymentList.AddRange(payment);
                        }

                        // Payment User
                        if (paymentList != null && paymentList.Count > 0)
                        {
                            foreach(var paymentObj in paymentList)
                            {
                                var payUser = new
                                {
                                    PaymentId = paymentObj.PaymentId,
                                    PaymentUser = paymentObj.CreatedUserAspNetUsers.Email
                                };
                                paymentUser.Add(payUser);
                            }
                        }

                        // Breakfast
                        if (isReservationBreakfast == false)
                        {
                            isReservationBreakfast = RR.RoomBreakfastList.Any(rb => rb.IsBreakfast == true);
                        }
                        
                    }
                }
                List<Countries> countries = context.Countries.Where(c => c.CountryId == c.CountryId).ToList();
                List<Source> source = context.Source.Where(s => s.HotelId == user.HotelId).ToList();
                List<Market> markets = context.Market.Where(m => m.HotelId == user.HotelId).ToList();
                List<Company> companys = context.Company.Where(c => c.HotelId == user.HotelId).ToList();
                var hotelFormRoomInvoice = context.HotelForm.Where(hf => hf.HotelId == user.HotelId && hf.FormType == "RoomInvoice").FirstOrDefault();
                var hotelFormRoomReceipt = context.HotelForm.Where(hf => hf.HotelId == user.HotelId && hf.FormType == "Receipt").FirstOrDefault();
                var colorGroup = reservation.Color;
                return Ok(new
                {
                    GroupLeader = groupLeader,
                    ReservationRooms = reservation.ReservationRoomsList.Select(rr => new {
                        ReservationRoomId = rr.ReservationRoomId,
                        ArrivalDate = rr.ArrivalDate,
                        DepartureDate = rr.DepartureDate,
                        Adults = rr.Adults,
                        Child = rr.Child,
                        Price = rr.Price,
                        BookingStatus = rr.BookingStatus,
                        IsGroupMaster = rr.IsGroupMaster,
                        Color = colorGroup,
                        IsCreateCard = rr.SmartCardList.Count() == 0 ? false : true,
                        Rooms = rr.Rooms,
                        Travellers = rr.Travellers,
                        RoomTypes = rr.RoomTypes,
                        RoomPrices = rr.RoomPrices,
                    }).ToList(),
                    GroupPayments = paymentList,
                    GroupPaymentUser = paymentUser,
                    countries = countries,
                    source = source,
                    markets = markets,
                    companys = companys,
                    GeneralInfo = new
                    {
                        Reservations = reservation,
                        PlanList = reservation.Hotels.RoomPricesList,
                        RoomTypeList = reservation.Hotels.RoomTypesList,
                        PaymentMethods = context.PaymentMethods,
                        Money = reservation.Hotels.MoneyList,
                        DefaultHotelMoneyId = reservation.Hotels.DefaultMoneyId,
                        CurrenciesISO = context.Currencies,
                        IsReservationBreakfast = isReservationBreakfast,
                        IsGroupCheckOut = isGroupCheckOut
                    },
                    GroupBalanceDueInfo = groupBalanceDueInfo,
                    MarketingInformation = new
                    {
                        Source = reservation.Source,
                        Market = reservation.Market,
                        Company = reservation.Company
                    },
                    RoomInvoice =  new
                    {
                        HotelFormRoomInvoice = hotelFormRoomInvoice,
                        HotelFormRoomReceipt = hotelFormRoomReceipt
                    }
                });
            }
            else
            {
                return Ok(BadRequest("INVALID_RESERVATION"));
            }
        }

        public class GroupCheckInModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupCheckIn")]
        public IHttpActionResult ProcessGroupCheckIn(GroupCheckInModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var conflictReservations = new List<Reservations>();
                var conflictRoomRepairs = new List<Rooms>();
                var successReservation = 0;
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && reservationRoom.BookingStatus == "BOOKED" && reservationRoom.RoomId != null && reservationRoom.ArrivalDate.Value.AddMinutes(currentHotel.TimeZoneOffset).Date <= DateTime.UtcNow.Date && (reservationRoom.DepartureDate > reservationRoom.ArrivalDate && reservationRoom.DepartureDate > DateTime.UtcNow))
                    {
                        var isValidRR = true;
                        var conflictReservationRoom = currentHotel.ReservationRoomsList.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != reservationRoom.ReservationRoomId && r.RoomId == reservationRoom.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN") || (r.ArrivalDate < reservationRoom.DepartureDate && reservationRoom.ArrivalDate <= r.DepartureDate))).ToList();
                        var conflictRepair = currentHotel.RoomRepairList.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == reservationRoom.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= reservationRoom.DepartureDate && reservationRoom.ArrivalDate <= rr.RepairEndDate)).ToList();
                        if (conflictReservationRoom != null && conflictReservationRoom.Count > 0)
                        {
                            isValidRR = false;
                            foreach (var conflictRR in conflictReservationRoom)
                            {
                                if (!conflictReservations.Exists(r => r.ReservationNumber == conflictRR.Reservations.ReservationNumber))
                                {
                                    conflictReservations.Add(conflictRR.Reservations);
                                }

                            }
                        }
                        if (conflictRepair != null && conflictRepair.Count > 0)
                        {
                            isValidRR = false;
                            foreach (var repair in conflictRepair)
                            {
                                if (!conflictRoomRepairs.Exists(r => r.RoomName == repair.Rooms.RoomName))
                                {
                                    conflictRoomRepairs.Add(repair.Rooms);
                                }

                            }
                        }
                        if (isValidRR)
                        {
                            successReservation += 1;
                            reservationRoom.ArrivalDate = DateTime.UtcNow;
                            reservationRoom.CheckInDate = DateTime.UtcNow;
                            reservationRoom.CheckInUserId = user.UserId;
                            reservationRoom.BookingStatus = "CHECKIN";
                            var rooms = reservationRoom.Rooms;
                            if (rooms != null && rooms.HouseStatus == "DIRTY")
                            {
                                rooms.HouseStatus = null;
                            }
                            var dateRange = new DateRange(reservationRoom.ArrivalDate.Value, reservationRoom.DepartureDate.Value);
                            ReservationUtility.RebuildRoomBreakfasts(dateRange, reservationRoom, user, context);
                            ReservationUtility.RebuildRoomCharges(dateRange, reservationRoom, user, context);
                            reservationRoomList.Add(reservationRoom);
                            Notification.processNotificationCheckin(user, rooms.RoomName);
                            //Notification.sendNotificationToDevice(user.UserName.ToLower(), user.FullName + " Checkin " + rooms.RoomName + " ", user.HotelId, "NOTIFICATION_CHECKEDIN");
                        }
                    }
                }
                context.SubmitChanges();
                
                foreach (var reservationRoom in reservationRoomList)
                {
                    ReservationUtility.RebuildAvailableRoom(reservationRoom, user, context);
                }
                Elastic.IndexLastAudit(context);
                return Ok(new
                {
                    groupFunctionCode = "GROUP_CHECKIN",
                    totalReservations = model.ReservationRoomIdList.Count,
                    unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                    successReservations = successReservation,
                });
            }
            return Ok(BadRequest("RESERVATION_DOES_NOT_EXIST"));
        }

        public class GroupCheckOutModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupCheckOut")]
        public async Task<IHttpActionResult> ProcessGroupCheckOut(GroupCheckOutModel model)
        {
            //if (!ModelState.IsValid)
            //{
            //    return BadRequest(ModelState);
            //}
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var successReservation = 0;
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && reservationRoom.BookingStatus == "CHECKIN")
                    {
                        var isValidRR = true;
                        var conflictReservationRoom = currentHotel.ReservationRoomsList.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId != reservationRoom.ReservationRoomId && r.RoomId == reservationRoom.RoomId && r.BookingStatus != "CHECKOUT" && r.BookingStatus != "CANCELLED" && ((r.BookingStatus == "CHECKIN") || (r.ArrivalDate < reservationRoom.DepartureDate && reservationRoom.ArrivalDate <= r.DepartureDate))).ToList();
                        var conflictRepair = currentHotel.RoomRepairList.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == reservationRoom.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= reservationRoom.DepartureDate && reservationRoom.ArrivalDate <= rr.RepairEndDate)).ToList();

                        if (conflictReservationRoom != null && conflictReservationRoom.Count > 0)
                        {
                            isValidRR = false;
                        }
                        if (conflictRepair != null && conflictRepair.Count > 0)
                        {
                            isValidRR = false;
                        }

                        if (isValidRR)
                        {
                            CalculateRoomPrice modelRoomPrice = new CalculateRoomPrice();
                            modelRoomPrice.roomId = reservationRoom.RoomId ?? 0;
                            modelRoomPrice.reservationRoomId = reservationRoom.ReservationRoomId;
                            modelRoomPrice.adults = reservationRoom.Adults;
                            modelRoomPrice.children = reservationRoom.Child;
                            modelRoomPrice.RoomPriceId = reservationRoom.RoomPriceId;
                            modelRoomPrice.FOC = reservationRoom.Foc;
                            modelRoomPrice.DiscountFlat = reservationRoom.DiscountFlat;
                            modelRoomPrice.DiscountPercentage = (float)reservationRoom.DiscountPercentage;
                            modelRoomPrice.languageKeys = model.languageKeys;
                            modelRoomPrice.Price = reservationRoom.Price;
                            modelRoomPrice.roomTypeId = (int)reservationRoom.RoomTypeId;

                            var oldPastCheckOut = reservationRoom.PastCheckOutList.FirstOrDefault();
                            if (oldPastCheckOut != null)
                            {
                                if (reservationRoom.DepartureDate >= DateTime.UtcNow)
                                {
                                    return BadRequest("INVALID_DEPARTURE_DATE_DUE_TO_PAST_CHECK_OUT");
                                }
                                else
                                {
                                    modelRoomPrice.departureDate = reservationRoom.DepartureDate ?? default(DateTime);
                                }
                            }
                            else
                            {
                                modelRoomPrice.departureDate = DateTime.UtcNow;
                            }
                            modelRoomPrice.arrivalDate = reservationRoom.ArrivalDate ?? default(DateTime);
                            var planListDateRange = await RoomPriceUtilities.CalculateRoomPrice(modelRoomPrice);
                            var roomExtraServices = reservationRoom.RoomExtraServicesList.Where(rex => !rex.IsDeleted).ToList();
                            var payments = reservationRoom.PaymentsList;
                            var totalPayment = payments.Sum(p => p.Amount);
                            var totalRoomPrice = planListDateRange.totalPrice + roomExtraServices.Sum(rex => rex.Amount);
                            int currentMinorUnit = Convert.ToInt16(context.Money.Where(mon => mon.HotelId == user.HotelId && mon.MoneyId == currentHotel.DefaultMoneyId).FirstOrDefault().Currencies.MinorUnit.ToString());
                            var roundMoney = Math.Round(totalRoomPrice.Value - totalPayment.Value, currentMinorUnit);
                            if (roundMoney == 0)
                            {
                                successReservation += 1;
                                reservationRoom.DepartureDate = modelRoomPrice.departureDate;
                                reservationRoom.BookingStatus = "CHECKOUT";

                                var changeReservationStatus = reservationRoom.ChangeReservationStatusList.FirstOrDefault(change => change.ActionCode == "PRE_CHECKOUT");
                                if (changeReservationStatus != null)
                                {
                                    reservationRoom.CheckOutDate = changeReservationStatus.ActionPoint;
                                }
                                else
                                {
                                    reservationRoom.CheckOutDate = DateTime.UtcNow;
                                }
                                reservationRoom.CheckOutUserId = user.UserId;

                                var room = reservationRoom.Rooms;
                                room.HouseStatus = "DIRTY";

                                // CREATE ROOM INVOICE PROCESS
                                ReservationUtility.CreateRoomInvoice(modelRoomPrice);

                                var dateRange = new DateRange(reservationRoom.ArrivalDate.Value, reservationRoom.DepartureDate.Value);
                                ReservationUtility.RebuildRoomBreakfasts(dateRange, reservationRoom, user, context);
                                ReservationUtility.RebuildRoomCharges(dateRange, reservationRoom, user, context);
                                reservationRoomList.Add(reservationRoom);

                                Notification.processNotificationCheckout(user, room.RoomName);
                            }
                        }
                    }
                }
                context.SubmitChanges();
                
                foreach (var reservationRoom in reservationRoomList)
                {
                    ReservationUtility.RebuildAvailableRoom(reservationRoom, user, context);
                }
                Elastic.IndexLastAudit(context);
                return Ok(new
                {
                    groupFunctionCode = "GROUP_CHECKOUT",
                    totalReservations = model.ReservationRoomIdList.Count,
                    unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                    successReservations = successReservation,
                });
            }
            return Ok(BadRequest("RESERVATION_DOES_NOT_EXIST"));

            
        }

        public class GroupRemoveReservationRoomModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessRemoveReservationRoomFromGroup")]
        public IHttpActionResult ProcessRemoveReservationRoomFromGroup(GroupRemoveReservationRoomModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var successReservation = 0;
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null)
                    {
                        successReservation += 1;
                        var newReservation = new Reservations()
                        {
                            CreatedDate = DateTime.UtcNow,
                            CreatedUserId = user.UserId,
                            HotelId = user.HotelId,
                            ReservationNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "RESERVATION"),
                        };
                        context.Reservations.InsertOnSubmit(newReservation);
                        reservationRoom.Reservations = newReservation;
                        
                    }
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
                return Ok(new
                {
                    groupFunctionCode = "REMOVE_RESERVATION_FROM_GROUP",
                    totalReservations = model.ReservationRoomIdList.Count,
                    unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                    successReservations = successReservation,
                });
            }

            return Ok(BadRequest("RESERVATION_DOES_NOT_EXIST"));
        }

        public class CancelGroupReservationModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public string CancelReason { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessCancelGroupReservation")]
        public IHttpActionResult ProcessCancelGroupReservation(CancelGroupReservationModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            string fullname = "";
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var successReservation = 0;
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null)
                    {
                        if (reservationRoom.BookingStatus == "BOOKED")
                        {
                            var payments = reservationRoom.PaymentsList.Where(p => p.RefPaymentId == null).ToList();
                            //var extraServices = reservationRoom.RoomExtraServicesList.Where(ex => ex.IsDeleted == false && (ex.RoomExtraServiceItemsList.Count > 0 && ex.RoomExtraServiceItemsList.Any(exi => exi.IsDeleted == false))).ToList(); 
                            var extraServices = reservationRoom.RoomExtraServicesList.Where(ex => ex.IsDeleted == false && ex.ReservationRoomId == reservationRoomId).ToList();
                            if (payments.Count == 0 && extraServices.Count == 0)
                            {
                                successReservation += 1;
                                reservationRoom.BookingStatus = "CANCELLED";
                                reservationRoom.CancelReason = model.CancelReason;
                                reservationRoomList.Add(reservationRoom);
                            }
                        }
                    }
                    
                }
                context.SubmitChanges();

                foreach (var reservationRoom in reservationRoomList)
                {
                    ReservationUtility.RebuildAvailableRoom(reservationRoom, user, context);
                }
                foreach (var reservationRoom in currentReservation.ReservationRoomsList)
                {
                    if (reservationRoom.IsGroupMaster == true)
                    {
                        fullname = reservationRoom.Travellers.Fullname;
                    }
                }
                if (successReservation > 0)
                {
                    Notification.processNotificationCanceledGroup(user, currentReservation.ReservationNumber, fullname, model.CancelReason, model.languageKeys["NOTIFICATION_CANCELED_GROUP_CONTENT"].ToString(), successReservation);
                    Elastic.IndexLastAudit(context);
                }
               
                return Ok(new
                {
                    groupFunctionCode = "CANCEL_GROUP_RESERVATION",
                    totalReservations = model.ReservationRoomIdList.Count,
                    unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                    successReservations = successReservation,
                });
            }

            return Ok(BadRequest("RESERVATION_DOES_NOT_EXIST"));
        }

        public class AutoAssignGroupRoomModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
        }
        
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAutoAssignGroupRoom")]
        public IHttpActionResult ProcessAutoAssignGroupRoom(AutoAssignGroupRoomModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
          
            
            var user = Common.UserUtitily.getUserProfile();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);

            var successReservation = 0;
            if (currentReservation != null)
            {
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null)
                    {
                        if (reservationRoom.BookingStatus == "BOOKED" &&  reservationRoom.RoomId == null)
                        {
                            var result = context.GroupReservationAutoAssignRoom(user.HotelId, reservationRoomId, (int)reservationRoom.RoomTypeId, (DateTime)reservationRoom.ArrivalDate, (DateTime)reservationRoom.DepartureDate);
                            if (result == 1)
                            {
                                successReservation += 1;
                            }
                        }

                       
                    }
                }
                Elastic.IndexLastAudit(context);
            }
            return Ok(new
            {
                groupFunctionCode = "AUTOASSIGN_GROUP_ROOM",
                totalReservations = model.ReservationRoomIdList.Count,
                unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                successReservations = successReservation,
            });
           
        }

        public class UnassignGroupRoomModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessUnassignGroupRoom")]
        public IHttpActionResult ProcessUnassignGroupRoom(UnassignGroupRoomModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var successReservation = 0;
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && reservationRoom.BookingStatus == "BOOKED")
                    {
                        successReservation += 1;
                        reservationRoom.RoomId = null;
                    }
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
                return Ok(new
                {
                    groupFunctionCode = "UNASSIGN_GROUP_ROOM",
                    totalReservations = model.ReservationRoomIdList.Count,
                    unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                    successReservations = successReservation,
                });
            }
            return Ok(BadRequest("RESERVATION_DOES_NOT_EXIST"));
        }

        public class ChangeOwnerShipModel
        {
            public int ReservationId { get; set; }
            public int ReservationRoomId { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessChangeOwnership")]
        public IHttpActionResult ProcessChangeOwnership(ChangeOwnerShipModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            //var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var newGroupMasterRR = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == model.ReservationRoomId);
                var oldGroupMasterRR = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.IsGroupMaster == true);
                if (newGroupMasterRR != null && oldGroupMasterRR != null)
                {
                    newGroupMasterRR.IsGroupMaster = true;
                    oldGroupMasterRR.IsGroupMaster = false;
                    context.SubmitChanges();
                    Elastic.IndexLastAudit(context);
                }
            }

            return Ok();
        }

        public class GroupDiscountModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public Boolean Foc { get; set; }
            public float DiscountPercentage { get; set; }
            public decimal DiscountFlat { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupDiscount")]
        public IHttpActionResult ProcessGroupDiscount(GroupDiscountModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            //var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                var conflictReservations = new List<Reservations>();
                var conflictRoomRepairs = new List<Rooms>();
                var successReservation = 0;
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && (reservationRoom.BookingStatus == "CHECKIN" || reservationRoom.BookingStatus == "BOOKED"))
                    {
                        successReservation += 1;
                        reservationRoom.Foc = model.Foc;
                        reservationRoom.DiscountPercentage = model.DiscountPercentage;
                        reservationRoom.DiscountFlat = model.DiscountFlat;

                        ApplyDiscountModel discountModel = new ApplyDiscountModel();
                        discountModel.FOC = model.Foc;
                        discountModel.reservationRoomId = reservationRoom.ReservationRoomId;
                        discountModel.DiscountFlat = model.DiscountFlat;
                        discountModel.DiscountPercentage =model.DiscountPercentage;
                        discountModel.languageKeys = model.languageKeys;

                        Notification.processNotificationDiscount(discountModel, user);


                    }
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
                return Ok(new
                {
                    groupFunctionCode = "GROUP_DISCOUNT",
                    totalReservations = model.ReservationRoomIdList.Count,
                    unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                    successReservations = successReservation,
                });
            }

            return Ok(BadRequest("RESERVATION_DOES_NOT_EXIST"));
        }

        public class GroupAmendStayModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public DateTime NewArrivalDate { get; set; }
            public DateTime NewDepartureDate { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupAmendStay")]
        public IHttpActionResult ProcessGroupAmendStay(GroupAmendStayModel model)
        {
            var user = Common.UserUtitily.getUserProfile();
            var currentHotel = context.Hotels.FirstOrDefault(ht => ht.HotelId == user.HotelId);
            if (currentHotel != null)
            {
                var currentReservation = currentHotel.ReservationsList.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
                if (currentReservation != null)
                {
                    var successReservation = 0;
                    var rrTempList = new List<ReservationRooms>();
                    var rrList = new List<ReservationRooms>();
                    var IsReservationCheckIn = context.ReservationRooms.Where(rr => model.ReservationRoomIdList.Contains(rr.ReservationRoomId) && rr.BookingStatus == "CHECKIN").ToList();
                    foreach (var reservationRoomId in model.ReservationRoomIdList)
                    {
                        var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);

                        if (reservationRoom != null && (reservationRoom.BookingStatus == "CHECKIN" || reservationRoom.BookingStatus == "BOOKED"))
                        {
                            
                            var isValidRR = true;

                            if (reservationRoom.RoomId != null)
                            {
                                //var conflictReservationRoom = currentHotel.ReservationRoomsList.Where(r => r.HotelId == user.HotelId 
                                //&& r.ReservationRoomId != reservationRoom.ReservationRoomId 
                                //&& r.RoomId == reservationRoom.RoomId 
                                //&& r.BookingStatus != "CHECKOUT" 
                                //&& r.BookingStatus != "CANCELLED" 
                                //&& ((r.BookingStatus == "CHECKIN") || (r.ArrivalDate < model.NewDepartureDate && model.NewArrivalDate <= r.DepartureDate))).ToList();
                                
                                if (reservationRoom.BookingStatus== "BOOKED")
                                {

                                    var conflictReservationRoom = currentHotel.ReservationRoomsList.Where(r => r.HotelId == user.HotelId
                                   && r.ReservationRoomId != reservationRoom.ReservationRoomId
                                   && r.RoomId == reservationRoom.RoomId
                                   && r.BookingStatus != "CHECKOUT"
                                   && r.BookingStatus != "CANCELLED"
                                   && r.ArrivalDate < model.NewDepartureDate 
                                   && model.NewArrivalDate <= r.DepartureDate).ToList();

                                    if (conflictReservationRoom != null && conflictReservationRoom.Count > 0)
                                    {
                                        isValidRR = false;
                                    }
                                }

                                if (reservationRoom.BookingStatus == "CHECKIN")
                                {

                                     var conflictReservationRoom = currentHotel.ReservationRoomsList.Where(r => r.HotelId == user.HotelId
                                   
                                    && r.ReservationRoomId != reservationRoom.ReservationRoomId
                                    && r.RoomId == reservationRoom.RoomId
                                    && r.BookingStatus != "CHECKOUT"
                                    && r.BookingStatus != "CANCELLED"
                                    && ((r.BookingStatus == "CHECKIN") || 
                                    (r.ArrivalDate < model.NewDepartureDate && model.NewArrivalDate <= r.DepartureDate))).ToList();

                                    if (conflictReservationRoom != null && conflictReservationRoom.Count > 0)
                                    {
                                        isValidRR = false;
                                    }
                                }

                                var conflictRepair = currentHotel.RoomRepairList.Where(rr => rr.HotelId == user.HotelId && rr.RoomId == reservationRoom.RoomId && rr.IsDeleted == false && (rr.RepairStartDate <= model.NewDepartureDate && model.NewArrivalDate <= rr.RepairEndDate)).ToList();

                               
                                if (conflictRepair != null && conflictRepair.Count > 0)
                                {
                                    isValidRR = false;
                                }
                            }
                            
                            if (isValidRR)
                            {
                                var RRTemp = new ReservationRooms();
                                var arrivalDate = reservationRoom.ArrivalDate;
                                var departureDate = reservationRoom.DepartureDate;
                                var roomTypeId = reservationRoom.RoomTypeId;
                                RRTemp.ArrivalDate = arrivalDate;
                                RRTemp.DepartureDate = departureDate;
                                RRTemp.RoomTypeId = roomTypeId;
                                rrTempList.Add(RRTemp);

                                
                                if (IsReservationCheckIn.Count() == 0)
                                {
                                    reservationRoom.ArrivalDate = model.NewArrivalDate;
                                }
                                if(model.NewDepartureDate > reservationRoom.ArrivalDate)
                                {
                                    successReservation = successReservation + 1;

                                    reservationRoom.DepartureDate = model.NewDepartureDate;
                                    rrList.Add(reservationRoom);

                                    var dateRange = new DateRange(reservationRoom.ArrivalDate.Value, reservationRoom.DepartureDate.Value);
                                    ReservationUtility.RebuildRoomBreakfasts(dateRange, reservationRoom, user, context);
                                    ReservationUtility.RebuildRoomCharges(dateRange, reservationRoom, user, context);
                                }
                            }
                            
                        }
                    }
                    context.SubmitChanges();
                    

                    // Consider only if hotel is using module "Channel Mananger"
                    // Room Available
                    foreach (var rr in rrList)
                    {
                        ReservationUtility.RebuildAvailableRoom(rr, user, context);
                    }

                    foreach (var rrTemp in rrTempList)
                    {
                        ReservationUtility.RebuildAvailableRoom(rrTemp, user, context);
                    }
                    Elastic.IndexLastAudit(context);
                    return Ok(new
                    {
                        groupFunctionCode = "GROUP_AMEND_STAY",
                        totalReservations = model.ReservationRoomIdList.Count,
                        unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                        successReservations = successReservation,
                    });
                }
            }

            return Ok(BadRequest("HOTEL_DOES_NOT_EXIST"));




        }

        public class GroupRateOperationModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public decimal NewRoomChargeAmount { get; set; }
            public Hashtable languageKeys { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupRateOperation")]
        public IHttpActionResult ProcessGroupRateOperation(GroupRateOperationModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            var successReservation = 0;
            if (currentReservation != null)
            {
                
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && (reservationRoom.BookingStatus == "CHECKIN" || reservationRoom.BookingStatus == "BOOKED"))
                    {
                        if (reservationRoom.Price != model.NewRoomChargeAmount)
                        {
                            EditPriceModel editPriceModel = new EditPriceModel();
                            editPriceModel.languageKeys = model.languageKeys;
                            editPriceModel.ReservationRoomId = reservationRoomId;
                            editPriceModel.NewPrice = model.NewRoomChargeAmount;
                            Notification.processNotificationEditPrice(editPriceModel, user, reservationRoom);
                        }
                        foreach (var roomCharge in reservationRoom.RoomChargesList)
                        {
                            successReservation = successReservation + 1;
                            roomCharge.Amount = model.NewRoomChargeAmount;
                        }

                        reservationRoom.Price = model.NewRoomChargeAmount;
                    }


                    
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok(new
            {
                groupFunctionCode = "GROUP_RATE_OPERATION",
                totalReservations = model.ReservationRoomIdList.Count,
                unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                successReservations = successReservation,
            });
        }

        public class GroupRateTypeOperationModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public int NewRoomPriceId { get; set; }
            public bool IsUpdatePrice { get; set; }
            public decimal NewPrice { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupRateTypeOperation")]
        public IHttpActionResult ProcessGroupRateTypeOperation(GroupRateTypeOperationModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            var successReservation = 0;
            if (currentReservation != null)
            {
                var newRoomPrice = context.RoomPrices.FirstOrDefault(rp => rp.HotelId == user.HotelId && rp.RoomPriceId == model.NewRoomPriceId);
                if (newRoomPrice != null)
                {
                    foreach (var reservationRoomId in model.ReservationRoomIdList)
                    {
                        var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                        if (reservationRoom != null && reservationRoom.BookingStatus != "CHECKOUT" && reservationRoom.BookingStatus != "CANCELLED")
                        {
                            successReservation = successReservation + 1;
                            //EditPriceModel model = new EditPriceModel();
                            reservationRoom.RoomPrices = newRoomPrice;
                            if (model.IsUpdatePrice)
                            {
                                reservationRoom.Price = (decimal)newRoomPrice.FullDayPrice;
                                foreach (var rc in reservationRoom.RoomChargesList)
                                {
                                    rc.Amount = reservationRoom.Price;
                                }
                            }
                            else
                            {
                                reservationRoom.Price = model.NewPrice;
                            }
                            
                        }
                    }
                    context.SubmitChanges();
                    Elastic.IndexLastAudit(context);
                }
            }
            return Ok(new
            {
                groupFunctionCode = "GROUP_RATE_TYPE_OPERATION",
                totalReservations = model.ReservationRoomIdList.Count,
                unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                successReservations = successReservation,
            });
        }

        public class GroupPaxOperationModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public int NewAdult { get; set; }
            public int NewChildren { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupPaxOperation")]
        public IHttpActionResult ProcessGroupPaxOperation(GroupPaxOperationModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            var successReservation = 0;
            if (currentReservation != null)
            {
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && (reservationRoom.BookingStatus == "CHECKIN" || reservationRoom.BookingStatus == "BOOKED"))
                    {
                        successReservation = successReservation + 1;
                        reservationRoom.Adults = model.NewAdult;
                        reservationRoom.Child = model.NewChildren;
                    }
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok(new
            {
                groupFunctionCode = "GROUP_PAX_OPERATION",
                totalReservations = model.ReservationRoomIdList.Count,
                unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                successReservations = successReservation,
            });
        }

        public class GroupBreakfastModel
        {
            public int ReservationId { get; set; }
            public List<int> ReservationRoomIdList { get; set; }
            public bool IsReservationBreakfast { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupBreakfast")]
        public IHttpActionResult ProcessGroupBreakfast(GroupBreakfastModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservationRoomList = new List<ReservationRooms>();
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            var successReservation = 0;
            if (currentReservation != null)
            {
                foreach (var reservationRoomId in model.ReservationRoomIdList)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == reservationRoomId);
                    if (reservationRoom != null && reservationRoom.BookingStatus != "CHECKOUT" && reservationRoom.BookingStatus != "CANCELLED")
                    {
                        successReservation = successReservation + 1;
                        foreach(var breakfast in reservationRoom.RoomBreakfastList)
                        {
                            breakfast.IsBreakfast = model.IsReservationBreakfast;
                        }
                    }
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok(new
            {
                groupFunctionCode = "GROUP_BREAKFAST",
                totalReservations = model.ReservationRoomIdList.Count,
                unsuccessReservations = model.ReservationRoomIdList.Count - successReservation,
                successReservations = successReservation,
            });
        }


        public class GroupPaymentModel
        {
            public int ReservationId { get; set; }
            public List<Payments> Payments { get; set; }
            public Hashtable languageKeys { get; set; }

        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupPayment")]
        public IHttpActionResult ProcessGroupPayment(GroupPaymentModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservationRoomList = new List<ReservationRooms>();
            var successReservation = 0;
            var currentReservation = context.Reservations.FirstOrDefault(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId);
            if (currentReservation != null)
            {
                
                var groupOrder = 0;
                var paymentNumber = InvoiceNumberGenerator.getInvoiceNumber(user.HotelId, "PAYMENT");
               
                foreach (var payment in model.Payments)
                {
                    var reservationRoom = currentReservation.ReservationRoomsList.FirstOrDefault(rr => rr.ReservationRoomId == payment.ReservationRoomId);
                    if (reservationRoom != null && (reservationRoom.BookingStatus == "CHECKIN" || reservationRoom.BookingStatus == "BOOKED"))
                    {
                        successReservation += 1;
                        groupOrder += 1;
                        payment.HotelId = user.HotelId;
                        payment.CreatedDate = DateTime.UtcNow;
                        payment.CreatedUserId = user.UserId;
                        payment.IsPaymentGroup = true;
                        payment.PaymentGroupCreatedDate = DateTime.UtcNow;
                        payment.PaymentGroupCreatedUserId = user.UserId;
                        payment.PaymentNumber = paymentNumber;
                        payment.PaymentGroupOrder = groupOrder;
                        payment.IsPaymentGroupDeleted = false;
                        context.Payments.InsertOnSubmit(payment);

                        PaymentModel paymentsModel = new PaymentModel();
                        paymentsModel.languageKeys = model.languageKeys;
                        paymentsModel.payment = payment;
                        Notification.processNotificationAddNewPayment(paymentsModel, user);
                    }
                }
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            return Ok(new
            {
                groupFunctionCode = "GROUP_PAYMENT",
                totalReservations = model.Payments.Count,
                unsuccessReservations = model.Payments.Count - successReservation,
                successReservations = successReservation,
            });
        }
        public class PaymentGroupModel
        {
            public Hashtable languageKeys { get; set; }
            public List<Payments> payment { get; set; }
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessDeleteGroupPayment")]
        public IHttpActionResult ProcessDeleteGroupPayment(PaymentGroupModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = Common.UserUtitily.getUserProfile();
            //if one of room in group is checkout, do not delete this payment 
            foreach (var payment in model.payment)
            {
                var RR = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationRoomId == payment.ReservationRoomId && r.BookingStatus=="CHECKOUT").FirstOrDefault();
                if (RR != null)
                { 
                   return BadRequest("CAN_NOT_PROCESS_DELETE_THIS_PAYMENT_BECAUSE_HAVE_ONE_OF_ROOM_CHECKOUT");
                }

            }

            var deletedPayments = new List<Payments>();
            foreach(var payment in model.payment)
            {
                var deletedPayment = new Payments();
                deletedPayment.HotelId = user.HotelId;
                deletedPayment.ReservationRoomId = payment.ReservationRoomId;
                deletedPayment.PaymentDescription = payment.PaymentDescription;
                deletedPayment.Amount = -1 * payment.Amount; // (payment.PaymentTypeName != "REFUND") ? payment.Amount : -payment.Amount;
                deletedPayment.CreatedDate = DateTime.UtcNow;
                deletedPayment.PaymentTypeName = "DELETED";
                deletedPayment.CreatedUserId = user.UserId;
                deletedPayment.PaymentMethodId = payment.PaymentMethodId;
                deletedPayment.MoneyId = payment.MoneyId;
                deletedPayment.AmountInSpecificMoney = payment.AmountInSpecificMoney;
                deletedPayment.PaymentNumber = payment.PaymentNumber;
                deletedPayment.IsPaymentGroup = true;
                deletedPayment.IsPaymentGroupDeleted = true;
                deletedPayment.PaymentGroupCreatedDate = DateTime.UtcNow;
                deletedPayment.PaymentGroupCreatedUserId = user.UserId;
                deletedPayment.PaymentGroupDeletedDate = DateTime.UtcNow;
                deletedPayment.PaymentGroupDeletedUserId = user.UserId;
                deletedPayment.RefPaymentId = payment.PaymentId;
                context.Payments.InsertOnSubmit(deletedPayment);
                deletedPayments.Add(deletedPayment);
                context.SubmitChanges();
                var originalPayment = context.Payments.FirstOrDefault(op => op.HotelId == user.HotelId && op.PaymentId == payment.PaymentId);
                if (originalPayment != null)
                {
                    originalPayment.PaymentGroupDeletedDate = DateTime.UtcNow;
                    originalPayment.PaymentGroupDeletedUserId = user.UserId;
                    originalPayment.IsPaymentGroupDeleted = true;
                    originalPayment.RefPaymentId = deletedPayment.PaymentId;
                }
                
            }
            context.SubmitChanges();
            //Notification for delete
            foreach (var payment in model.payment)
            {
                PaymentModel paymentsmodel = new PaymentModel();
                paymentsmodel.languageKeys = model.languageKeys;
                paymentsmodel.payment = payment;
                Notification.processNotificationDeletePayment(paymentsmodel, user);
            }
            Elastic.IndexLastAudit(context);
            return Ok();
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAddReservationToGroup")]
        public async Task<IHttpActionResult> ProcessAddReservationToGroup(MergeGroupModel model)
        {
            if (model == null || model.ListReservationId.Count() ==0 || model.NewReservationId == 0) 
                return BadRequest("Reservation rooms is null");
            var user = Common.UserUtitily.getUserProfile();
            var oldReservationId = model.ListReservationId[0];
            var reservation = context.Reservations.Where(rr => rr.HotelId == user.HotelId && rr.ReservationId == oldReservationId).FirstOrDefault();
            var reservationRooms = context.ReservationRooms.Where(r => r.HotelId == user.HotelId && r.ReservationId == oldReservationId).FirstOrDefault();
            if(reservation != null && reservationRooms != null)
            {
                reservation.IsEmpty = true;
                reservationRooms.IsGroupMaster = false;
                reservationRooms.ReservationId = model.NewReservationId;
                context.SubmitChanges();
            }
            return Ok(reservationRooms);
        }


        public class AddNewLeaderModel
        {
            public int ReservationId { get; set; }
            public Travellers traveller { get; set; }
        };
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessAddNewLeader")]
        public async Task<IHttpActionResult> ProcessAddNewLeader(AddNewLeaderModel model)
        {

            if (model == null || model.ReservationId == 0)
            {
                return BadRequest("MODEL IS NULL");
            }

            var user = Common.UserUtitily.getUserProfile();
            var reservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == user.HotelId && rr.ReservationId == model.ReservationId && rr.IsGroupMaster == true).FirstOrDefault();
            if (reservationRooms == null)
            {
                return BadRequest();
            }

            model.traveller.CreatedDate = DateTime.UtcNow;
            model.traveller.CreatedUserId = user.UserId;
            model.traveller.HotelId = user.HotelId;
            context.Travellers.InsertOnSubmit(model.traveller);
            context.SubmitChanges();
            //
            reservationRooms.TravellerId = model.traveller.TravellerId;
            context.SubmitChanges();

            Common.Elastic.IndexLastAudit(context);

            return Ok();
        }
        public class EditGroupModel
        {
            public int ReservationId { set; get; }
            public string NewNote { set; get; }
            public string NewColor { set; get; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditNote")]
        public async Task<IHttpActionResult> EditNote(EditGroupModel model)
        {
            if (model == null || model.ReservationId == 0 || model.NewNote == "" || model.NewNote == null)
            {
                return BadRequest("Model Is Null");
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservation = context.Reservations.Where(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId).FirstOrDefault();
            if (reservation == null)
            {
                return BadRequest("Reservation Not Exists");
            }
            reservation.Note = model.NewNote;
            context.SubmitChanges();
            return Ok(model.ReservationId);
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("EditColor")]
        public async Task<IHttpActionResult> EditColor(EditGroupModel model)
        {
            if (model == null || model.ReservationId == 0 || model.NewColor == "" || model.NewColor == null)
            {
                return BadRequest("Model Is Null");
            }
            var user = Common.UserUtitily.getUserProfile();
            var reservation = context.Reservations.Where(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId).FirstOrDefault();
            if (reservation == null)
            {
                return BadRequest("Reservation Not Exists");
            }
            reservation.Color = model.NewColor;
            context.SubmitChanges();
            MemoryCacher.ClearStatusCache(user.HotelId);
            return Ok(model.ReservationId);
        }
        public class ReservationCompany
        {
            public Company Company { get; set; }
            public int ReservationId { get; set; }
        }
        public class ReservationSource
        {
            public Source Source { get; set; }
            public int ReservationId { get; set; }
        }
        public class ReservationMarket
        {
            public Market Market { get; set; }
            public int ReservationId { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddNewCompanyToReservation")]
        public async Task<IHttpActionResult> AddNewCompanyToReservation(ReservationCompany model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = UserUtitily.getUserProfile();

            model.Company.IsAvailable = true;
            model.Company.CreatedDate = DateTime.UtcNow;
            model.Company.CreatedUserId = user.UserId;
            model.Company.HotelId = user.HotelId;
            model.Company.SourceId = model.Company.SourceId == 0 ? null : model.Company.SourceId;
            context.Company.InsertOnSubmit(model.Company);
            context.SubmitChanges();
            //Elastic.IndexLastAudit(context);
            var reservation = context.Reservations.Where(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId).FirstOrDefault();
            if (reservation == null)
            {
                return BadRequest("RESERVATION IS NOT EXISTS");
            }
            //reservation.Company = model.Company;
            reservation.CompanyId = model.Company.CompanyId;
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
            return Ok(model.Company);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddNewSourceToReservation")]
        public async Task<IHttpActionResult> AddNewSourceToReservation(ReservationSource model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = UserUtitily.getUserProfile();

            model.Source.IsAvailable = true;
            model.Source.CreatedDate = DateTime.UtcNow;
            model.Source.CreatedUserId = user.UserId;
            model.Source.HotelId = user.HotelId;
            context.Source.InsertOnSubmit(model.Source);
            context.SubmitChanges();
            //Elastic.IndexLastAudit(context);
            var reservation = context.Reservations.Where(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId).FirstOrDefault();
            if (reservation == null)
            {
                return BadRequest("RESERVATION IS NOT EXISTS");
            }
            //reservation.Source = model.Source;
            reservation.SourceId = model.Source.SourceId;
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
            return Ok(model.Source);
        }

        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("AddNewMarketToReservation")]
        public async Task<IHttpActionResult> AddNewMarketToReservation(ReservationMarket model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var user = UserUtitily.getUserProfile();

            model.Market.IsAvailable = true;
            model.Market.CreatedDate = DateTime.UtcNow;
            model.Market.CreatedUserId = user.UserId;
            model.Market.HotelId = user.HotelId;
            context.Market.InsertOnSubmit(model.Market);
            context.SubmitChanges();
            //Elastic.IndexLastAudit(context);
            var reservation = context.Reservations.Where(r => r.HotelId == user.HotelId && r.ReservationId == model.ReservationId).FirstOrDefault();
            if (reservation == null)
            {
                return BadRequest("RESERVATION IS NOT EXISTS");
            }
            //reservation.Market = model.Market;
            reservation.MarketId = model.Market.MarketId;
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
            return Ok(model.Market);
        }
        public class BusinessModel
        {
            public int ReservationId { get; set; }
            public Company Company { get; set; }
            public Source Source { get; set; }
            public Market Market { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SaveBusiness")]
        public IHttpActionResult SaveBusiness(BusinessModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var user = UserUtitily.getUserProfile();
            var reservation = context.Reservations.FirstOrDefault(rr => rr.HotelId == user.HotelId && rr.ReservationId == model.ReservationId);
            if (reservation != null)
            {
                reservation.MarketId = model.Market?.MarketId ?? null;
                reservation.SourceId = model.Source?.SourceId ?? null;
                reservation.CompanyId = model.Company?.CompanyId ?? null;
                context.SubmitChanges();
                Elastic.IndexLastAudit(context);
            }
            else
            {
                return BadRequest("RESERVATION IS NOT EXISTS");
            }
            return Ok();
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("CreateGroupInvoice")]
        public async Task<IHttpActionResult> CreateGroupInvoice(CalculateGroupPrice model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var context = new ezCloudDataContext();
            var currentClientUser = Common.UserUtitily.getUserProfile();

            var currentHotel = context.Hotels.Where(ht => ht.HotelId == currentClientUser.HotelId).FirstOrDefault();
            var listReservationRooms = context.ReservationRooms.Where(rr => rr.HotelId == currentClientUser.HotelId && rr.ReservationId == model.ReservationId).ToList();
            if (listReservationRooms.Count() > 0)
            {
                foreach (ReservationRooms currentReservationRoom in listReservationRooms)
                {
                    if (currentReservationRoom.BookingStatus != "CHECKOUT" && currentReservationRoom.BookingStatus != "CANCELLED" )
                    {
                        CalculateRoomPrice modelRoomPrice = new CalculateRoomPrice();
                        modelRoomPrice.roomId = currentReservationRoom.RoomId ?? 0;
                        modelRoomPrice.reservationRoomId = currentReservationRoom.ReservationRoomId;
                        modelRoomPrice.adults = currentReservationRoom.Adults;
                        modelRoomPrice.children = currentReservationRoom.Child;
                        modelRoomPrice.RoomPriceId = currentReservationRoom.RoomPriceId;
                        modelRoomPrice.FOC = currentReservationRoom.Foc;
                        modelRoomPrice.DiscountFlat = currentReservationRoom.DiscountFlat;
                        modelRoomPrice.DiscountPercentage = (float)currentReservationRoom.DiscountPercentage;
                        modelRoomPrice.languageKeys = model.languageKeys;
                        modelRoomPrice.Price = currentReservationRoom.Price;
                        modelRoomPrice.roomTypeId = (int)currentReservationRoom.RoomTypeId;
                        //
                        var oldPastCheckOut = currentReservationRoom.PastCheckOutList.FirstOrDefault();
                        if (oldPastCheckOut != null)
                        {
                            if (currentReservationRoom.DepartureDate >= DateTime.UtcNow)
                            {
                                return BadRequest("INVALID_DEPARTURE_DATE_DUE_TO_PAST_CHECK_OUT");
                            }
                            else
                            {
                                modelRoomPrice.departureDate = currentReservationRoom.DepartureDate ?? default(DateTime);
                            }
                        }
                        else
                        {
                            //modelRoomPrice.departureDate = DateTime.UtcNow;
                            modelRoomPrice.departureDate = currentReservationRoom.DepartureDate?? default(DateTime);
                        }
                        modelRoomPrice.arrivalDate = currentReservationRoom.ArrivalDate ?? default(DateTime);
                        ReservationUtility.CreateRoomInvoice(modelRoomPrice);
                    }
                };

            }
            return Ok();
        }
        public class GroupCancelModel
        {
            public int ReservationId { set; get; }
            public string CancelReason { set; get; }
            public Hashtable languageKeys { get; set; }
        }
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("ProcessGroupCancel")]
        public IHttpActionResult ProcessGroupCancel(GroupCancelModel model)
        {
            var currentClientUser = Common.UserUtitily.getUserProfile();
            var ListReservationRooms = context.ReservationRooms.Where(rr => rr.ReservationId == model.ReservationId && rr.HotelId == currentClientUser.HotelId).ToList();
            if(ListReservationRooms.Count() == 0)
            {
                return Ok("GROUP_DOES_NOT_EXIST");
            }
            foreach(ReservationRooms rr in ListReservationRooms)
            {
                
                if (rr.BookingStatus == "CHECKIN" || rr.BookingStatus == "CHECKOUT")
                {
                    return Ok("GROUP_HAVE_RESERVATION_IS_CHECKIN_PLEASE_PROCESS_BEFORE_CANCEL");
                }
            }
            var extraService = context.RoomExtraServices.Where(es => es.ReservationRooms.ReservationId == model.ReservationId && es.HotelId == currentClientUser.HotelId && es.IsDeleted == false).ToList();
            if (extraService.Count() > 0)
            {
                return Ok("RESERVATION_IN_GROUP_HAS_EXTRA_SERVICE_PLEASE_PROCESS_BEFORE_CANCEL");
            }

            decimal payment = 0;
            var listPayment = context.Payments.Where(p => p.ReservationRooms.ReservationId == model.ReservationId && (p.IsPaymentGroupDeleted == false || p.IsPaymentGroupDeleted == null) && p.HotelId == currentClientUser.HotelId).ToList();
            payment = listPayment.Sum(s => s.Amount).Value;
            if (payment > 0)
            {
                return Ok("RESERVATION_IN_GROUP_HAS_PAYMENT_OR_DEPOIST_PLEASE_PROCESS_BEFORE_CANCEL");
            }
            int ReservationNumber = 0;
            string fullname = "";
            //process
            foreach (ReservationRooms rr in ListReservationRooms)
            {
                ReservationNumber = rr.Reservations.ReservationNumber.Value;
                rr.CancelReason = model.CancelReason;
                rr.BookingStatus = "CANCELLED";
                if (rr.IsGroupMaster == true)
                {
                    fullname = rr.Travellers.Fullname;
                }
            }
            context.SubmitChanges();
            
            // Room Available
            foreach (ReservationRooms rr in ListReservationRooms)
            {
                ReservationUtility.RebuildAvailableRoom(rr, currentClientUser, context);
            }
            

            Notification.processNotificationCanceledGroup(currentClientUser, ReservationNumber, fullname, model.CancelReason, model.languageKeys["NOTIFICATION_CANCELED_GROUP_CONTENT"].ToString(), ListReservationRooms.Count());
            //Notification.processNotificationCanceledGroup(currentClientUser, ReservationNumber);

            Common.MemoryCacher.ClearStatusCache(currentClientUser.HotelId);
            Common.Elastic.IndexLastAudit(context);

            return Ok("SUCCESSFUL");
        }
    }
}